package com.espirit.init;


import java.util.ArrayList;
import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.stereotype.Service;

import com.espirit.eap.ValidationUtil;
import com.espirit.eap.manager.DBAManager;
import com.espirit.eap.manager.Department;
import com.espirit.eap.manager.Dictionary;
import com.espirit.eap.manager.DictionaryService;
import com.espirit.eap.manager.EapI18nData;
import com.espirit.eap.manager.I18n;
import com.espirit.eap.manager.I18nService;
import com.espirit.eap.manager.Menu;
import com.espirit.eap.manager.MenuService;
import com.espirit.eap.manager.SystemData;
import com.espirit.eap.manager.SystemDataService;
import com.espirit.eap.manager.TaskScheduler;
import com.espirit.eap.pagelayout.FunctionButton;
import com.espirit.eap.pagelayout.Model;
import com.espirit.eap.pagelayout.ModelService;
import com.espirit.eap.pagelayout.PageUpgradeService;
import com.espirit.eap.sa.Employee;
import com.espirit.eap.sa.PrivilegeService;
import com.espirit.eap.sa.ScopeType;
import com.espirit.eap.sa.Template;
import com.espirit.eap.sa.User;
import com.espirit.eap.sa.UserTemplate;
import com.espirit.eap.sa.WebsiteService;
import com.espirit.finance.core.Acct;
import com.espirit.finance.core.AcctItem;
import com.espirit.finance.core.AcctItemRef;
import com.espirit.hr.DeliveryTimeItem;
import com.espirit.hr.DutyRecord;
import com.espirit.hr.FaultItem;
import com.espirit.hr.HrSetting;
import com.espirit.hr.LeaveAppItem;
import com.espirit.hr.OtItem;
import com.espirit.hr.SalaryAcctItemRef;
import com.espirit.hr.Schedual;
import com.espirit.hr.SchedualRecord;
import com.googlecode.cswish.model.ModelInfo;
import com.googlecode.cswish.struts.ContextHolder;
import com.googlecode.cswish.struts.spring.BeanIntrospector;
import com.googlecode.cswish.struts.spring.GenericService;


/**
 * Manage DataBase
 * 	 
 */
@Service
public class DBAService extends DBAManager {
	private static final Log logger = LogFactory.getLog(DBAService.class);
	
	@Resource
	private BeanIntrospector beanIntrospector;
	
	@Resource
	protected MenuService menuService;
	
	@Resource
	protected GenericService genericService;
	
	@Resource
	private I18nService i18nService;
		
	@Resource
	protected ValidationUtil genericServiceUtil;
	
	
	@Resource
	private WebsiteService websiteService;
	
	@Resource
	private ModelService modelService;
	
	@Resource
	private PrivilegeService privilegeService;
	
	@Resource
	private PageUpgradeService pageUpgradeService;
	
	@Resource
	SystemDataService systemDataService;
	
	@Resource
	DictionaryService dictionaryService;
	
	@Resource
	EapI18nData eapI18nData;
	
	// these model is shared by all websites
	
	//position : 职位
	static  final String POSITION = "position"; 

	
	@Override
	public void initDB(String initModel) {
		super.initDB(initModel);
		
		systemDataService.setValue(SystemData.ENABLE_SYSTEMLOG, "true");
		systemDataService.setValue(SystemData.FORCE_USE_SYSTEMLAYOUT, "true");
	}
	static final String[] modelPackages = new String[]{"com.espirit.init.base"
													,"com.espirit.init.biz"};
	public DBAService() {
		
	}
	
	@Override
	public boolean init() {
		logger.debug("begin init data.................");
		initDB("create-drop");
		initModel();
		initModelInitData();
		saveI18nData(eapI18nData);
		initSystemData();
		logger.debug("finished init data successfully!!!!!!");
		return true;
	}
	
	public boolean fastInit(){
		initDB("create-drop");
		initModel();
		initModelInitData();
		fastInitSystemData();
		return true;
	}
	
	public void fastInitSystemData() {
		initMenuData();
		initAllPrivileges();
		fastInitTemplate();
		initBizData();
	}
	
	@Override
	public void initSystemData() {
		initMenuData();
		initAllPrivileges();
		initDefaultTemplate();
		initBizData();
		
	}
	
	public void initModel() {
		for(String modelPackage : modelPackages){
			super.builderModel(modelPackage);
		}
	}
	
	public void upgradeModel(){
		for(String modelPackage : modelPackages){
			super.builderModel(modelPackage);
		}
	}
	
	@Override
	public void initModelInitData() {
		for(String modelPackage : modelPackages){
			super.builderModelInitData(modelPackage);
		}
	}
	
	public void initMenuData(){
		logger.debug("init menu data...");
//		String site = ContextHolder.get().getSiteName();
		String site = "espirit";
		
		Menu menuPermission = menuService.createMenu("permission", "Permission","权限", null, "espirit");
		menuService.createMenu(Department.class, menuPermission, site);
		menuService.createMenu(User.class, menuPermission, site);
		menuService.createMenu(Employee.class, menuPermission, site);
		
		Menu menuHr = menuService.createMenu("hr", "HR", "人力运营", null, site);
		menuService.createMenu(LeaveAppItem.class, menuHr, site);
		menuService.createMenu(OtItem.class, menuHr, site);
		menuService.createMenu(DeliveryTimeItem.class, menuHr, site);
		menuService.createMenu(FaultItem.class, menuHr, site);
		
		menuService.createMenu(DutyRecord.class, menuHr, site);
		menuService.createMenu(Schedual.class, menuHr, site);
		menuService.createMenu(SchedualRecord.class, menuHr, site);
		menuService.createMenu(HrSetting.class, FunctionButton.PREUPDATE, menuHr, site);
	}
	
	ModelInfo mi = null;
	public void initAllPrivileges(){
		
		String m_add = "_add";
		String m_update = "_update";
		String m_delete = "deleteList";
		String m_search = "search";
		String m_export = "export";
		
		List<String> methods = new ArrayList<String>();
		methods.add(m_add);
		methods.add(m_update);
		methods.add(m_delete);
		methods.add(m_search);
		methods.add(m_export);
		
		List<ScopeType> scopes = new ArrayList<ScopeType>();
		scopes.add(ScopeType.Basic);
		scopes.add(ScopeType.Deep);
		scopes.add(ScopeType.Global);
		scopes.add(ScopeType.Local);
		
		addCommonPrivilege(scopes, methods);
		addManagerPrivilege(scopes, methods);
		addHrPrivilege(scopes, methods);
		addEapPrivilege(scopes, methods);
	}
	
	private String getI18nKey(String cnName, String enName){
		I18n i18n = i18nService.addI18n(cnName, enName);
		return i18n.getKey();
	}
	
	private void addCommonPrivilege(List<ScopeType> scopes, List<String> methods){
		List<Model> models = getPackageModels("espirit.common");
		for(Model model: models){
			String modelName = model.getName();
			String fullModelName = beanIntrospector.getModelName(modelName);
			mi = beanIntrospector.getModelInfo(fullModelName);
			
			if (modelName.endsWith("sysLog")){
				addSearchScopePrivilege(modelName, scopes);
				addMethodGlobalPrivilege(modelName, FunctionButton.PREADD);
			} else {
				for(String method : methods){
					addMethodGlobalPrivilege(modelName, method);
				}
			}
		}
	}
	
	private void addHrPrivilege(List<ScopeType> scopes, List<String> methods){
		List<Model> models = getPackageModels("espirit.hr");
		for(Model model: models){
			String modelName = model.getName();
			String fullModelName = beanIntrospector.getModelName(modelName);
			mi = beanIntrospector.getModelInfo(fullModelName);
			
			for(String method : methods){
				addMethodGlobalPrivilege(modelName, method);
			}
		}
	}
	
	private void addEapPrivilege(List<ScopeType> scopes, List<String> methods){
		List<Model> models = getPackageModels("espirit.eap");
		for(Model model: models){
			String modelName = model.getName();
			String fullModelName = beanIntrospector.getModelName(modelName);
			mi = beanIntrospector.getModelInfo(fullModelName);
			
			for(String method : methods){
				addMethodGlobalPrivilege(modelName, method);
			}
			if (modelName.endsWith("privilege")){
				addMethodGlobalPrivilege(modelName, "applySelectedPrivileges");
			}
		}
	}
	
	private void addManagerPrivilege(List<ScopeType> scopes, List<String> methods){
		List<Model> models = getPackageModels("espirit.manager");
		for(Model model: models){
			String modelName = model.getName();
			String fullModelName = beanIntrospector.getModelName(modelName);
			mi = beanIntrospector.getModelInfo(fullModelName);
			
			for(String method : methods){
				addMethodGlobalPrivilege(modelName, method);
			}
		}
	}
	
	
	private void addGetLayoutPrivilege(String modelName){
		addMethodGlobalPrivilege(modelName, "getLayout");
	}
	private void addCommonPrivilege(Model model,List<String> methods,List<ScopeType> scopes){
		String modelName = model.getName();
		if (mi.getProperty("owner") != null){
			for(String method : methods){
				addMethodScopePrivilege(modelName, method, scopes);
			}
		} else {
			for(String method : methods){
				addMethodGlobalPrivilege(modelName, method);
			}
		}
	}
	
	private void addImportPrivilege(String modelName){
		addMethodGlobalPrivilege(modelName, "_importFile");
	}
	
	private void addSearchGlobalPrivilege(String modelName){
		addMethodGlobalPrivilege(modelName, "search");
	}

	private void addPreSearchScopePrivilege(String modelName, List<ScopeType> scopes){
		addMethodScopePrivilege(modelName, "_search", scopes);
	}

	
	private void addSearchScopePrivilege(String modelName, List<ScopeType> scopes){
		addMethodScopePrivilege(modelName,"search",  scopes);
	}
	
	private void addMethodScopePrivilege(String modelName,String method , List<ScopeType> scopes){
		for(ScopeType scopeType : scopes){
			addMethodScopePrivile(modelName, method, scopeType);
		}
	}
	
	private void addMethodGlobalPrivilege(String modelName,String method){
		addMethodScopePrivile(modelName, method, ScopeType.Global);
	}
	
	private void addMethodGlobalPrivilege(String modelName,String method, String i18n){
		addMethodScopePrivile(modelName, method, ScopeType.Global, i18n);
	}
	
	public void addMethodScopePrivile(String modelSimpleName,String method ,ScopeType scopeType){
		addMethodScopePrivile(modelSimpleName, method, scopeType, null);
	}

	public void addMethodScopePrivile(String modelSimpleName,String method ,ScopeType scopeType, String i18n){
		privilegeService.addMethodScopePrivile(modelSimpleName, method, scopeType, i18n);
	}
	
	private void addBackPrivilege(String modelName){
		addMethodGlobalPrivilege(modelName, "back");
	}
	
	private void addGoNextPrivilege(String modelName){
		addMethodGlobalPrivilege(modelName, "_goNext");
	}
	
	public void fastInitTemplate(){
		
	}
	
	public void initDefaultTemplate(){
		logger.debug("init default privilege data....");

		Template t_admin = new Template();
		t_admin.setName("管理员");
		t_admin.setDescription("admin");
		t_admin = genericServiceUtil.checkAndAdd(t_admin);
		addAllPrivilege(t_admin);

		fastInitTemplate();
		
		logger.debug("finished init default privilege data.");
	}
	
	private void addAllPrivilege(UserTemplate ut){
		setUtCategoryPrivilege(ut,  "espirit.common");
		setUtCategoryPrivilege(ut, "espirit.eap");
		
		String bizSite = ContextHolder.get().getSiteName();
		setUtCategoryPrivilege(ut, bizSite + ".hr");
		setUtCategoryPrivilege(ut, bizSite + ".operation");
	}
	
	
	public void initBizData(){
		initTaskSchedulerData();
		resetPluginUpdateTime();
		initDictionaryData();
		initSalaryAcctItemRefs();
	}
	
	public void initUpgradeBizData(){
		initTaskSchedulerData();
		resetPluginUpdateTime();
		initDictionaryData();
		initSalaryAcctItemRefs();
	}
	
	private void initSalaryAcctItemRefs(){
		addSalaryAcctItemRef("基本工资", "employee.fixedSalary");
		addSalaryAcctItemRef("外卖次数", "deliveryTims");
		addSalaryAcctItemRef("过失", "falutAmount");
		addSalaryAcctItemRef("加班", "otHours");
		addSalaryAcctItemRef("请假", "leaveAppHours");
		addSalaryAcctItemRef("迟到", "lateItems.minutes");
		addSalaryAcctItemRef("早退", "leaveEarlyItems.minutes");
		addSalaryAcctItemRef("旷工", "absentDays");
	}
	
	private void addSalaryAcctItemRef(String name, String property){
		SalaryAcctItemRef salaryAcctItemRef = new SalaryAcctItemRef();
		salaryAcctItemRef.setName(name);
		salaryAcctItemRef.setProperty(property);
		genericServiceUtil.checkAndAdd(salaryAcctItemRef);
	}
	
	
	
	private void resetPluginUpdateTime() {
		pageUpgradeService.resetUpgradeTime();
	}
	
	private void initDictionaryData(){
		//POSITION : 职位
		dictionaryService.mergeByTypeValue(new Dictionary("总经理", "1", POSITION));
		dictionaryService.mergeByTypeValue(new Dictionary("副总经理", "2", POSITION));
		dictionaryService.mergeByTypeValue(new Dictionary("区域经理", "3", POSITION));
		dictionaryService.mergeByTypeValue(new Dictionary("服务员", "4", POSITION));
		dictionaryService.mergeByTypeValue(new Dictionary("收银员", "5", POSITION));
		dictionaryService.mergeByTypeValue(new Dictionary("厨师", "6", POSITION));
		dictionaryService.mergeByTypeValue(new Dictionary("店长", "7", POSITION));
		
		dictionaryService.mergeByTypeValue(new Dictionary("事假", LeaveAppItem.LEAVE_TYPE_CASUAL.toString(), LeaveAppItem.LEAVE_TYPE));
		dictionaryService.mergeByTypeValue(new Dictionary("病假", LeaveAppItem.LEAVE_TYPE_SICK.toString(), LeaveAppItem.LEAVE_TYPE));
		dictionaryService.mergeByTypeValue(new Dictionary("调休", LeaveAppItem.LEAVE_TYPE_OFF.toString(), LeaveAppItem.LEAVE_TYPE));

		dictionaryService.mergeByTypeValue(new Dictionary("借方", Acct.DC_DEBIT.toString(), Acct.DC));
		dictionaryService.mergeByTypeValue(new Dictionary("贷方", Acct.DC_CREDIT.toString(), Acct.DC));

		dictionaryService.mergeByTypeValue(new Dictionary("常规", Acct.STRATEGY_GENERAL.toString(), Acct.ACCT_CALC_STRATEGY));
		dictionaryService.mergeByTypeValue(new Dictionary("固定", Acct.STRATEGY_FIXED.toString(), Acct.ACCT_CALC_STRATEGY));

		dictionaryService.mergeByTypeValue(new Dictionary("阶梯单价", AcctItem.STRATEGY_STYLE_PER_PRICE.toString(), AcctItem.ACCOUNT_CALC_STRATEGY_STYLE));
		dictionaryService.mergeByTypeValue(new Dictionary("阶梯金额", AcctItem.STRATEGY_STYLE_PER_AMOUNT.toString(), AcctItem.ACCOUNT_CALC_STRATEGY_STYLE));
		dictionaryService.mergeByTypeValue(new Dictionary("属性", AcctItem.STRATEGY_STYLE_PROPERTY.toString(), AcctItem.ACCOUNT_CALC_STRATEGY_STYLE));

	}
	
	private void initTaskSchedulerData() {
		// fix rate 1 hour
		checkAndAddTaskScheduler("Clean Invalid Login User",
				"com.googlecode.cswish.security.SafeManager.cleanInvalidLoginUser",
				"3600000", "每隔1小时");
		
		// 22:00 am every day (night)
		checkAndAddTaskScheduler("Backup DB",
				"com.espirit.eap.manager.DbBackupHistoryService.backupDb",
				"0 0 22 * * ?", "每晚10点");
	}
	
	private void checkAndAddTaskScheduler(String name, String command, String cond, String desc) {
		TaskScheduler example = new TaskScheduler();
		example.setName(name);
		TaskScheduler taskScheduler = genericService.searchAll(example).getData(0);
		if (taskScheduler == null) {
			taskScheduler = example;
		}
		
		taskScheduler.setCommand(command);
		taskScheduler.setCond(cond);
		taskScheduler.setActive(true);
		taskScheduler.setDescription(desc);
		genericService.merge(taskScheduler);
	}
	
	@Override
	public void initI18nData() {
		saveI18nData(eapI18nData);
	}
}